package com.learning.spring.security.base.config;

import org.springframework.aop.Advisor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Role;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreFilter;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.authorization.method.AuthorizationInterceptorsOrder;
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.PostFilterAuthorizationMethodInterceptor;
import org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.core.GrantedAuthorityDefaults;

/**
 * ClassName: MethodSecurityConfig
 * Description: 方法安全
 * Date: 2022/7/11 14:39
 *
 * @author Sam Sho
 * @version V1.0.0
 */
@EnableMethodSecurity
//@EnableGlobalMethodSecurity
public class MethodSecurityConfig {

    /**
     * 自定义授权
     */
    static class CustomizingAuthorization {
        /**
         * 如果你需要自定义表达式的处理方式，你可以公开一个自定义 MethodSecurityExpressionHandler
         * <p>
         * 原来使用 @EnableGlobalMethodSecurity注解时，需要扩展 GlobalMethodSecurityConfiguration 配置类来定制
         *
         * @return
         */
        @Bean
        static MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
            DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
            // 自定义解析
            handler.setTrustResolver(new AuthenticationTrustResolverImpl());
            return handler;
        }

        /**
         * 对于基于角色的授权，Spring Security 添加了一个默认的 ROLE_ 前缀，它在计算 hasRole 等表达式时使用。
         * 可以通过暴露一个 GrantedAuthorityDefaults 的 bean 对象实现配置授权规则使用一个不同的前缀
         *
         * @return
         */
        @Bean
        static GrantedAuthorityDefaults grantedAuthorityDefaults() {
            return new GrantedAuthorityDefaults("MYPREFIX_");
        }
    }

    /**
     * 自定义授权管理器.
     * <p>
     * 要重新创建默认情况下添加@EnableMethodSecurity所做的事情，需要发布以下配置
     */
    @EnableMethodSecurity(prePostEnabled = false)
    static class CustomAuthorizationManagers {

        /**
         * @return
         * @see PreFilter
         */
        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        Advisor preFilterAuthorizationMethodInterceptor() {
            return new PreFilterAuthorizationMethodInterceptor();
        }

        /**
         * @return
         * @see PreAuthorize
         */
        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        Advisor preAuthorizeAuthorizationMethodInterceptor() {
            return AuthorizationManagerBeforeMethodInterceptor.preAuthorize();
        }

        /**
         * @return
         * @see PostAuthorize
         */
        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        Advisor postAuthorizeAuthorizationMethodInterceptor() {
            return AuthorizationManagerAfterMethodInterceptor.postAuthorize();
        }

        /**
         * @return
         * @see PostFilter
         */
        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        Advisor postFilterAuthorizationMethodInterceptor() {
            return new PostFilterAuthorizationMethodInterceptor();
        }


    }

    static class CustomAuthorizationManagers2 {

        /**
         * Spring Security 的方法安全性是使用 Spring AOP构建的。
         * 因此，拦截器是根据指定的顺序调用的。这可以通过对拦截器实例调用setOrder来定制
         *
         * @return
         */
        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        Advisor postFilterAuthorizationMethodInterceptor() {
            PostFilterAuthorizationMethodInterceptor interceptor = new PostFilterAuthorizationMethodInterceptor();
            interceptor.setOrder(AuthorizationInterceptorsOrder.POST_AUTHORIZE.getOrder() - 1);
            return interceptor;
        }

        /**
         * 添加到列表中的方法前的自定义 AuthorizationManager
         * @return
         */
/*        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public Advisor customAuthorize() {
            // 需要告诉 Spring Security AuthorizationManager 以及您的授权管理器应用哪些方法和类
            JdkRegexpMethodPointcut pattern = new JdkRegexpMethodPointcut();
            pattern.setPattern("org.mycompany.myapp.service.*");

            // 这个方法已经删除了
            AuthorizationManager<MethodInvocation> rule = AuthorityAuthorizationManager.isAuthorized();
            AuthorizationManagerBeforeMethodInterceptor interceptor = new AuthorizationManagerBeforeMethodInterceptor(pattern, rule);
            interceptor.setOrder(AuthorizationInterceptorsOrder.PRE_AUTHORIZE.getOrder() + 1);
            return interceptor;
        }*/


        /**
         * 自定义注解
         *
         * @param rules
         * @return
         */
        /*@Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public Advisor customAuthorize(AuthorizationManager<MethodInvocationResult> rules) {
            AnnotationMethodMatcher pattern = new AnnotationMethodMatcher(MySecurityAnnotation.class);
            AuthorizationManagerAfterMethodInterceptor interceptor = new AuthorizationManagerAfterMethodInterceptor(pattern, rules);
            interceptor.setOrder(AuthorizationInterceptorsOrder.POST_AUTHORIZE.getOrder() + 1);
            return interceptor;
        }*/

        @interface MySecurityAnnotation {

        }

    }


}